<template>
  <section class="demo-section">
    <div class="demo-header">
      <h2 class="demo-title">4. defineModel 双向绑定 (Vue 3.4+)</h2>
      <p class="demo-description">
        defineModel 是 Vue 3.4+ 引入的组合式 API，专门用于简化组件的双向绑定实现。
        它提供了一种更直观、更简洁的方式来处理 v-model
        指令，大大减少了样板代码，提升了开发体验。
      </p>
    </div>

    <div class="demo-content">
      <!-- 基础双向绑定演示 -->
      <div class="demo-card">
        <h3 class="card-title">📝 基础双向绑定</h3>
        <div class="demo-area">
          <div class="input-section">
            <label>用户名:</label>
            <CustomInput v-model="username" placeholder="请输入用户名" />
          </div>
          <div class="input-section">
            <label>邮箱:</label>
            <CustomInput v-model="email" placeholder="请输入邮箱地址" />
          </div>
          <div class="input-section">
            <label>密码:</label>
            <CustomInput v-model="password" type="password" placeholder="请输入密码" />
          </div>

          <div class="preview-box">
            <h4>实时预览:</h4>
            <p><strong>用户名:</strong> {{ username || "未填写" }}</p>
            <p><strong>邮箱:</strong> {{ email || "未填写" }}</p>
            <p>
              <strong>密码:</strong>
              {{ password ? "*".repeat(password.length) : "未填写" }}
            </p>
          </div>
        </div>
      </div>

      <!-- 多重绑定演示 -->
      <div class="demo-card">
        <h3 class="card-title">🔗 多重 v-model 绑定</h3>
        <div class="demo-area">
          <UserConfigPanel
            v-model:theme="userTheme"
            v-model:fontSize="userFontSize"
            v-model:autoSave="userAutoSave"
            v-model:language="userLanguage"
          />

          <div class="config-preview">
            <h4>配置预览:</h4>
            <div class="config-item">
              <span>主题:</span>
              <span class="config-value" :class="userTheme">{{ themeText }}</span>
            </div>
            <div class="config-item">
              <span>字体大小:</span>
              <span class="config-value" :style="{ fontSize: userFontSize + 'px' }">
                {{ userFontSize }}px
              </span>
            </div>
            <div class="config-item">
              <span>自动保存:</span>
              <span class="config-value" :class="{ active: userAutoSave }">
                {{ userAutoSave ? "开启" : "关闭" }}
              </span>
            </div>
            <div class="config-item">
              <span>语言:</span>
              <span class="config-value">{{ languageText }}</span>
            </div>
          </div>
        </div>
      </div>

      <!-- 验证器演示 -->
      <div class="demo-card">
        <h3 class="card-title">✅ 带验证的模型</h3>
        <div class="demo-area">
          <div class="validation-section">
            <label>邮箱验证 (必须包含@符号):</label>
            <ValidatedInput
              v-model="validatedEmail"
              :validator="emailValidator"
              placeholder="请输入有效邮箱"
            />
            <span
              class="validation-status"
              :class="{ valid: isEmailValid, invalid: !isEmailValid && validatedEmail }"
            >
              {{ emailValidationMessage }}
            </span>
          </div>

          <div class="validation-section">
            <label>密码强度 (8-20位，包含字母和数字):</label>
            <ValidatedInput
              v-model="validatedPassword"
              :validator="passwordValidator"
              type="password"
              placeholder="请输入强密码"
            />
            <span
              class="validation-status"
              :class="{
                valid: isPasswordValid,
                invalid: !isPasswordValid && validatedPassword,
              }"
            >
              {{ passwordValidationMessage }}
            </span>
          </div>

          <div class="validation-section">
            <label>年龄 (18-100岁):</label>
            <ValidatedInput
              v-model.number="validatedAge"
              :validator="ageValidator"
              type="number"
              placeholder="请输入年龄"
            />
            <span
              class="validation-status"
              :class="{ valid: isAgeValid, invalid: !isAgeValid && validatedAge }"
            >
              {{ ageValidationMessage }}
            </span>
          </div>
        </div>
      </div>

      <!-- 代码对比演示 -->
      <div class="demo-card">
        <h3 class="card-title">📊 传统方式 vs defineModel</h3>
        <div class="comparison">
          <div class="comparison-column">
            <h4>❌ 传统方式 (Vue 3.3)</h4>
            <div class="code-example">
              <pre><code>&lt;script setup&gt;
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

const value = computed({
  get: () => props.modelValue,
  set: val => emit('update:modelValue', val)
})
&lt;/script&gt;

&lt;template&gt;
  &lt;input v-model="value" /&gt;
&lt;/template&gt;</code></pre>
            </div>
          </div>

          <div class="comparison-column">
            <h4>✅ defineModel (Vue 3.4+)</h4>
            <div class="code-example">
              <pre><code>&lt;script setup&gt;
const model = defineModel()
&lt;/script&gt;

&lt;template&gt;
  &lt;input v-model="model" /&gt;
&lt;/template&gt;</code></pre>
            </div>
          </div>
        </div>

        <div class="benefits">
          <h4>🚀 优势对比:</h4>
          <ul>
            <li>✅ <strong>代码量减少 70%</strong> - 从 8 行减少到 2 行</li>
            <li>✅ <strong>零样板代码</strong> - 无需手动编写 props、emit 和 computed</li>
            <li>✅ <strong>类型安全</strong> - 自动类型推导，更好的 TypeScript 支持</li>
            <li>✅ <strong>开发体验</strong> - 更直观的 API，降低心智负担</li>
          </ul>
        </div>
      </div>
    </div>
  </section>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";

// 基础双向绑定数据
const username = ref("");
const email = ref("");
const password = ref("");

// 多重绑定数据
const userTheme = ref("light");
const userFontSize = ref(16);
const userAutoSave = ref(true);
const userLanguage = ref("zh-CN");

// 验证器数据
const validatedEmail = ref("");
const validatedPassword = ref("");
const validatedAge = ref<number | null>(null);

// 计算属性
const themeText = computed(() => {
  return userTheme.value === "light" ? "浅色主题" : "深色主题";
});

const languageText = computed(() => {
  const languages: Record<string, string> = {
    "zh-CN": "简体中文",
    "en-US": "English",
    "ja-JP": "日本語",
  };
  return languages[userLanguage.value] || userLanguage.value;
});

// 验证器函数
const emailValidator = (value: string) => {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
};

const passwordValidator = (value: string) => {
  return /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,20}$/.test(value);
};

const ageValidator = (value: number) => {
  return value >= 18 && value <= 100;
};

// 验证状态
const isEmailValid = computed(
  () => !validatedEmail.value || emailValidator(validatedEmail.value)
);
const isPasswordValid = computed(
  () => !validatedPassword.value || passwordValidator(validatedPassword.value)
);
const isAgeValid = computed(
  () => validatedAge.value === null || ageValidator(validatedAge.value)
);

// 验证消息
const emailValidationMessage = computed(() => {
  if (!validatedEmail.value) return "请输入邮箱";
  return isEmailValid.value ? "✅ 邮箱格式正确" : "❌ 邮箱格式不正确";
});

const passwordValidationMessage = computed(() => {
  if (!validatedPassword.value) return "请输入密码";
  return isPasswordValid.value
    ? "✅ 密码强度符合要求"
    : "❌ 密码需8-20位，包含字母和数字";
});

const ageValidationMessage = computed(() => {
  if (validatedAge.value === null) return "请输入年龄";
  return isAgeValid.value ? "✅ 年龄符合要求" : "❌ 年龄必须在18-100岁之间";
});
</script>

<!-- 自定义组件定义 -->
<script lang="ts">
import { defineComponent } from "vue";

// 简单输入框组件
export const CustomInput = defineComponent({
  props: {
    modelValue: String,
    placeholder: String,
    type: { type: String, default: "text" },
  },
  emits: ["update:modelValue"],
  setup(props, { emit }) {
    const updateValue = (event: Event) => {
      const target = event.target as HTMLInputElement;
      emit("update:modelValue", target.value);
    };

    return { updateValue };
  },
  template: `
    <input 
      :value="modelValue"
      @input="updateValue"
      :type="type"
      :placeholder="placeholder"
      class="custom-input"
    />
  `,
});

// 用户配置面板组件
export const UserConfigPanel = defineComponent({
  props: {
    theme: String,
    fontSize: Number,
    autoSave: Boolean,
    language: String,
  },
  emits: ["update:theme", "update:fontSize", "update:autoSave", "update:language"],
  setup(props, { emit }) {
    return {
      updateTheme: (value: string) => emit("update:theme", value),
      updateFontSize: (value: number) => emit("update:fontSize", value),
      updateAutoSave: (value: boolean) => emit("update:autoSave", value),
      updateLanguage: (value: string) => emit("update:language", value),
    };
  },
  template: `
    <div class="config-panel">
      <div class="config-group">
        <label>主题:</label>
        <select :value="theme" @change="updateTheme($event.target.value)" class="config-select">
          <option value="light">浅色主题</option>
          <option value="dark">深色主题</option>
        </select>
      </div>
      
      <div class="config-group">
        <label>字体大小: {{ fontSize }}px</label>
        <input 
          type="range" 
          :value="fontSize" 
          @input="updateFontSize(Number($event.target.value))"
          min="12" 
          max="24" 
          class="config-range"
        />
      </div>
      
      <div class="config-group">
        <label>
          <input 
            type="checkbox" 
            :checked="autoSave" 
            @change="updateAutoSave($event.target.checked)"
            class="config-checkbox"
          />
          自动保存
        </label>
      </div>
      
      <div class="config-group">
        <label>语言:</label>
        <select :value="language" @change="updateLanguage($event.target.value)" class="config-select">
          <option value="zh-CN">简体中文</option>
          <option value="en-US">English</option>
          <option value="ja-JP">日本語</option>
        </select>
      </div>
    </div>
  `,
});

// 带验证的输入框组件
export const ValidatedInput = defineComponent({
  props: {
    modelValue: [String, Number],
    validator: Function,
    placeholder: String,
    type: { type: String, default: "text" },
  },
  emits: ["update:modelValue"],
  setup(props, { emit }) {
    const updateValue = (event: Event) => {
      const target = event.target as HTMLInputElement;
      const value = props.type === "number" ? Number(target.value) : target.value;
      emit("update:modelValue", value);
    };

    return { updateValue };
  },
  template: `
    <input 
      :value="modelValue"
      @input="updateValue"
      :type="type"
      :placeholder="placeholder"
      class="validated-input"
    />
  `,
});
</script>

<style scoped>
.demo-section {
  background: white;
  margin-bottom: 3rem;
  border-radius: 16px;
  padding: 2rem;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.05);
}

.demo-header {
  margin-bottom: 2rem;
}

.demo-title {
  font-size: 1.8rem;
  font-weight: 600;
  color: #2c3e50;
  margin-bottom: 1rem;
}

.demo-description {
  font-size: 1rem;
  color: #64748b;
  line-height: 1.7;
  background: #f8fafc;
  padding: 1rem;
  border-radius: 8px;
  border-left: 4px solid #667eea;
}

.demo-content {
  display: grid;
  gap: 2rem;
}

.demo-card {
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  padding: 1.5rem;
  background: #fafbfc;
}

.card-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: #2c3e50;
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.demo-area {
  display: grid;
  gap: 1.5rem;
}

.input-section {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.input-section label {
  font-weight: 600;
  color: #374151;
}

.custom-input,
.validated-input {
  padding: 0.75rem 1rem;
  border: 2px solid #e2e8f0;
  border-radius: 8px;
  font-size: 1rem;
  transition: all 0.3s ease;
}

.custom-input:focus,
.validated-input:focus {
  outline: none;
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.preview-box {
  background: white;
  padding: 1rem;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
  margin-top: 1rem;
}

.preview-box h4 {
  margin: 0 0 0.5rem 0;
  color: #374151;
}

.preview-box p {
  margin: 0.25rem 0;
  color: #64748b;
}

.config-panel {
  display: grid;
  gap: 1rem;
  background: white;
  padding: 1rem;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
}

.config-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.config-group label {
  font-weight: 600;
  color: #374151;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.config-select,
.config-range,
.config-checkbox {
  padding: 0.5rem;
  border: 2px solid #e2e8f0;
  border-radius: 6px;
}

.config-select:focus,
.config-range:focus {
  outline: none;
  border-color: #667eea;
}

.config-preview {
  background: white;
  padding: 1rem;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
}

.config-preview h4 {
  margin: 0 0 1rem 0;
  color: #374151;
}

.config-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem 0;
  border-bottom: 1px solid #f1f5f9;
}

.config-item:last-child {
  border-bottom: none;
}

.config-value {
  font-weight: 600;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  transition: all 0.3s ease;
}

.config-value.light {
  background: #fef3c7;
  color: #92400e;
}

.config-value.dark {
  background: #374151;
  color: white;
}

.config-value.active {
  background: #dcfce7;
  color: #166534;
}

.validation-section {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.validation-section label {
  font-weight: 600;
  color: #374151;
}

.validation-status {
  font-size: 0.9rem;
  font-weight: 500;
  padding: 0.25rem 0;
}

.validation-status.valid {
  color: #059669;
}

.validation-status.invalid {
  color: #dc2626;
}

.comparison {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
  margin-bottom: 2rem;
}

.comparison-column h4 {
  margin: 0 0 1rem 0;
  color: #374151;
}

.code-example {
  background: #1e293b;
  color: #e2e8f0;
  padding: 1rem;
  border-radius: 8px;
  font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
  font-size: 0.9rem;
  overflow-x: auto;
}

.code-example pre {
  margin: 0;
  white-space: pre-wrap;
}

.benefits {
  background: #f0f9ff;
  padding: 1.5rem;
  border-radius: 8px;
  border: 1px solid #0ea5e9;
}

.benefits h4 {
  margin: 0 0 1rem 0;
  color: #0c4a6e;
}

.benefits ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.benefits li {
  padding: 0.5rem 0;
  color: #0369a1;
  line-height: 1.5;
}

@media (max-width: 768px) {
  .comparison {
    grid-template-columns: 1fr;
  }

  .demo-area {
    gap: 1rem;
  }

  .config-panel {
    gap: 0.75rem;
  }
}
</style>
